/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to jorya.txj@gmail.com
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/


/* 	2012-8  Created by jorya_txj
  *	xxxxxx   please added here
  */


#include <raw_api.h>
#include <posix/pthread.h>
#include <posix/errno.h>
#include <mm/raw_page.h>
#include <mm/raw_malloc.h>
#include <lib_string.h>
#include <fifo.h>
#include <rsh.h>
#include <device/device_interface.h>


#pragma comment( lib, "Winmm.lib" )



extern RAW_U32 test_page_mem[1024*1024];

RAW_U16 raw_os_start();




void start_vc_timer(int tick_ms);


extern void  vc_port_printf(char*   f,   ...);

RAW_U32 thread_count1;
RAW_U32 thread_count2;
RAW_U32 thread_count3;
RAW_U32 thread_count4;
RAW_U32 thread_count5;
RAW_U32 thread_count6;


void *test_thread2(void * pParam);

void *test_thread3(void * pParam);

void *test_thread4(void * pParam);
void *test_thread5(void * pParam);
void *test_thread6(void * pParam);

struct raw_fifo fifo;
int fifo_data;

pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
pthread_t thread4;
pthread_t thread5;
pthread_t thread6;


extern int raw_sprintf(char *out, const char *format, ...);

RAW_S8 out_put_shell[1024];


static RAW_U32 first_command_case(RAW_S8 *pcWriteBuffer,
                                          size_t xWriteBufferLen,
                                          const RAW_S8 *pcCommandString )
{
    /* For simplicity, this function assumes the output buffer is large enough
    to hold all the text generated by executing the vTaskList() API function,
    so the xWriteBufferLen parameter is not used. */
    ( void ) xWriteBufferLen;

	vc_port_printf("first_command_case running\n");
	
    /* The entire table was written directly to the output buffer.  Execution
    of this command is complete, so return pdFALSE. */
    return 1;
}
		


static RAW_U32 first_command_case2(RAW_S8 *pcWriteBuffer,
                                          size_t xWriteBufferLen,
                                          const RAW_S8 *pcCommandString )
{
    /* For simplicity, this function assumes the output buffer is large enough
    to hold all the text generated by executing the vTaskList() API function,
    so the xWriteBufferLen parameter is not used. */
    ( void ) xWriteBufferLen;

	vc_port_printf("first_command_case2 running\n");
	
    /* The entire table was written directly to the output buffer.  Execution
    of this command is complete, so return pdFALSE. */
    return 1;
}

static RAW_U32 lParameterNumber;

static RAW_U32 command_case_three_parameters(RAW_S8 *pcWriteBuffer, size_t xWriteBufferLen, const RAW_S8 *pcCommandString )
{
	RAW_S8 *pcParameter;
	RAW_U32 lParameterStringLength, xReturn;
	

	/* Remove compile time warnings about unused parameters, and check the
	write buffer is not NULL.  NOTE - for simplicity, this example assumes the 
	write buffer length is adequate, so does not check for buffer overflows. */
	( void ) pcCommandString;
	( void ) xWriteBufferLen;
	

	if( lParameterNumber == 0 )
	{
		/* The first time the function is called after the command has been
		entered just a header string is returned. */
		raw_sprintf( ( char * ) pcWriteBuffer, "The three parameters were:\r\n" );

		/* Next time the function is called the first parameter will be echoed
		back. */
		lParameterNumber = 1L;

		/* There is more data to be returned as no parameters have been echoed
		back yet. */
		xReturn = 0;
	}
	else
	{
		/* Obtain the parameter string. */
		pcParameter = (RAW_S8 *) rsh_get_parameter
									( 
										pcCommandString,		/* The command string itself. */
										lParameterNumber,		/* Return the next parameter. */
										&lParameterStringLength	/* Store the parameter string length. */
									);

		/* Sanity check something was returned. */
		if (pcParameter == 0) {

			RAW_ASSERT(0);
		}

		/* Return the parameter string. */
		raw_memset( pcWriteBuffer, 0x00, xWriteBufferLen );
		raw_sprintf( ( char * ) pcWriteBuffer, "%d: ", lParameterNumber );
		raw_strncat( ( char * ) pcWriteBuffer, ( const char * ) pcParameter, lParameterStringLength );
		raw_strncat( ( char * ) pcWriteBuffer, "\r\n", raw_strlen( "\r\n" ) );

		/* If this is the last of the three parameters then there are no more
		strings to return after this one. */
		if( lParameterNumber == 3L )
		{
			/* If this is the last of the three parameters then there are no more
			strings to return after this one. */
			xReturn = 1;
			lParameterNumber = 0L;
		}
		else
		{
			/* There are more parameters to return after this one. */
			xReturn = 0;
			lParameterNumber++;
		}
	}

	return xReturn;
}



static RAW_U32 second_command_case(RAW_S8 *pcWriteBuffer,
                                          size_t xWriteBufferLen,
                                          const RAW_S8 *pcCommandString )
{
    /* For simplicity, this function assumes the output buffer is large enough
    to hold all the text generated by executing the vTaskList() API function,
    so the xWriteBufferLen parameter is not used. */
    ( void ) xWriteBufferLen;

	vc_port_printf("aa\n");
	
    /* The entire table was written directly to the output buffer.  Execution
    of this command is complete, so return pdFALSE. */
    return 1;
}


static RAW_U32 third_command_case(RAW_S8 *pcWriteBuffer,
                                          size_t xWriteBufferLen,
                                          const RAW_S8 *pcCommandString )
{
    /* For simplicity, this function assumes the output buffer is large enough
    to hold all the text generated by executing the vTaskList() API function,
    so the xWriteBufferLen parameter is not used. */
    ( void ) xWriteBufferLen;

	vc_port_printf("aaa\n");
	
    /* The entire table was written directly to the output buffer.  Execution
    of this command is complete, so return pdFALSE. */
    return 1;
}


static const xCommandLineInput test_rsh_command = 
{
	( const RAW_S8 * const ) "test",
	( const RAW_S8 * const ) "test: only test!\n",
	first_command_case,
	0
};


static const xCommandLineInput test_rsh_command2 = 
{
	( const RAW_S8 * const ) "tes222222",
	( const RAW_S8 * const ) "test22222: only test2222222!\n",
	first_command_case2,
	0
};

static const xCommandLineInput test_rsh_command3 = 
{
	( const RAW_S8 * const ) "aa",
	( const RAW_S8 * const ) "test: only testaa!\n",
	second_command_case,
	0
};


static const xCommandLineInput test_rsh_command4 = 
{
	( const RAW_S8 * const ) "aaa",
	( const RAW_S8 * const ) "aaa22222: only aaa2222222!\n",
	third_command_case,
	0
};



static const xCommandLineInput three_parameters_case =
{
	( const RAW_S8 * const ) "echo_3_parameters",
	( const RAW_S8 * const ) "\necho_3_parameters <param1> <param2> <param3>:\r\n Expects three parameters, echos each in turn\n",
	command_case_three_parameters, /* The function to run. */
	3 /* Three parameters are expected, which can take any value. */
};

static RAW_U8 fifo_space[16];

RAW_U8 fifo_received_data[16];

static xCommandLineInputListItem pxNewListItem1;
static xCommandLineInputListItem pxNewListItem2;
static xCommandLineInputListItem pxNewListItem3;

static xCommandLineInputListItem pxNewListItem4;
static xCommandLineInputListItem pxNewListItem5;


void test_thread(void * pParam) 
{	
	RAW_S32 ret;
	RAW_S32 received_bytes;
	
	int aa = 0x55;
	int bb = 0x56;
	
	vc_port_printf("passing argument is %x\n", *(RAW_U32 *)pParam);
	
	raw_page_init(test_page_mem, test_page_mem + 1024*1024);
	raw_malloc_init();
	
	fifo_init(&fifo, fifo_space, 16);
	fifo_in(&fifo, &aa, 4);
	fifo_in(&fifo, &bb, 4);

	fifo_out(&fifo, &fifo_data, 4);
	fifo_out(&fifo, &fifo_data, 4);
	fifo_in(&fifo, &bb, 4);
	fifo_in(&fifo, &bb, 4);
	fifo_in(&fifo, &bb, 4);
	fifo_out(&fifo, &fifo_data, 4);
	received_bytes = fifo_out_all(&fifo, fifo_received_data);
	fifo_data = 0;
	
	fifo_out(&fifo, &fifo_data, 4);

	rsh_register_command(&test_rsh_command, &pxNewListItem1);
	rsh_register_command(&test_rsh_command2, &pxNewListItem2);
	rsh_register_command(&three_parameters_case, &pxNewListItem3);

	rsh_register_command(&test_rsh_command3, &pxNewListItem4);
	rsh_register_command(&test_rsh_command4, &pxNewListItem5);

	do {

		ret = rsh_process_command("help", out_put_shell, 1024);
		vc_port_printf("%s\n", out_put_shell);
		
	} while (ret == 0);

	do {
		ret = rsh_process_command("tes222222", out_put_shell, 1024);
	} while (ret == 0);


	do {
		ret = rsh_process_command("bb1", out_put_shell, 1024);
		vc_port_printf("%s\n", out_put_shell);
	} while (ret == 0);
	

	do {
		ret = rsh_process_command("aa", out_put_shell, 1024);
		vc_port_printf("%s\n", out_put_shell);
	} while (ret == 0);

	do {
		ret = rsh_process_command("aaa", out_put_shell, 1024);
	} while (ret == 0);

	
	do {
		ret = rsh_process_command("echo_3_parameters 1 2 3", out_put_shell, 1024);
		vc_port_printf("%s\n", out_put_shell);
	} while (ret == 0);

	raw_open("/I2C3/", 0);
	
	pthread_create(&thread2, 0, test_thread2, 0);
	pthread_create(&thread3, 0, test_thread3, 0);
	pthread_create(&thread4, 0, test_thread4, 0);
	pthread_create(&thread5, 0, test_thread5, 0);
	pthread_create(&thread6, 0, test_thread6, 0);
	
	raw_task_delete(raw_task_identify());
	
}

volatile double angle2 =2.0;
volatile double angle3 =3.0;
volatile double angle4 =4.0;
volatile double angle5 =5.0;

void *test_thread2(void * pParam) 
{	
	RAW_U8 old_priority;
	
	raw_task_priority_change(raw_task_identify(), 4, &old_priority);
	raw_task_delete(&thread6->task_obj);
	
	while(1) {
    
		vc_port_printf("angle2 is %f\n", angle2);
		vc_port_printf("angle3 is %f\n", angle3);
		vc_port_printf("angle4 is %f\n", angle4);
		vc_port_printf("angle5 is %f\n", angle5);
		
		raw_sleep(RAW_TICKS_PER_SECOND);
		
	}
}

void *test_thread3(void * pParam) 
{	
	
	while(1) {

		angle3 +=  (angle2 + angle4)/(angle3+angle4 +angle5);

		angle2 = (angle3 + angle4)/(angle3 + angle4 + angle5 + angle2);
	}
}


void *test_thread4(void * pParam) 
{	
	
	while(1) {
		
		angle4 +=  0.534*(angle2 + 3*angle4)/(angle2+angle3+angle4 +angle5);
		raw_sleep(1);
	}
}


void *test_thread5(void * pParam) 
{	
	
	while(1) {	

		angle5 +=  0.0000001 * (angle2 * angle3)/((angle2*angle3)+(angle4 *angle5));
		
	}
}


void *test_thread6(void * pParam) 
{	
	
	while(1) {	

		thread_count6++;
		
	}
}



RAW_TASK_OBJ 		test_thread_obj;
#define  TEST_TASK_STK_SIZE 10240

PORT_STACK test_thread_stack[TEST_TASK_STK_SIZE];

extern RAW_U8 test_started_raw;
RAW_U32 aaa;

void thread_test()
{
	
	
	if (test_started_raw) {

		return;

	}

	test_started_raw = 1;

	aaa = 0x99887766;
	
	raw_task_create(&test_thread_obj, (RAW_U8  *)"task1", &aaa,
	                         3, 0,  test_thread_stack, 
	                         TEST_TASK_STK_SIZE, test_thread, RAW_TASK_AUTO_START); 
	

}

